#import "AnyThinkCrashFilter.h"
#import <dlfcn.h>
#import <stdint.h>


@interface AnyThinkCrashFilter()
#pragma mark - 地址范围存储
/// AnyThinkSDK 内存起始地址（包含 ASLR 偏移）
@property (nonatomic, assign) uintptr_t sdkStartAddress;
/// AnyThinkSDK 内存结束地址（包含 ASLR 偏移）
@property (nonatomic, assign) uintptr_t sdkEndAddress;
/// 地址范围是否有效（避免未初始化时误判）
@property (nonatomic, assign, readonly) BOOL isAddressRangeValid;
@end

@implementation AnyThinkCrashFilter

#pragma mark - 单例初始化
+ (instancetype)sharedInstance {
    static AnyThinkCrashFilter *instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[AnyThinkCrashFilter alloc] init];
    });
    return instance;
}



- (BOOL)isAddressRangeValid {
    return (self.sdkStartAddress > 0 && self.sdkEndAddress > self.sdkStartAddress);
}

#pragma mark - 计算 AnyThinkSDK 地址范围
- (void)setupWithSDKIdentifier:(NSString *)libraryIdentifier {
    if (libraryIdentifier.length == 0) {
        NSLog(@"[AnyThinkCrashFilter] 错误：SDK 标识为空，无法计算地址范围");
        return;
    }

    // 重置地址范围（防止重复初始化）
    self.sdkStartAddress = 0;
    self.sdkEndAddress = 0;

    // 遍历所有已加载的二进制镜像
    const uint32_t imageCount = _dyld_image_count();
    NSLog(@"[AnyThinkCrashFilter] 开始搜索 SDK 标识 '%@'，共 %u 个镜像", libraryIdentifier, imageCount);
    
    for (uint32_t i = 0; i < imageCount; i++) {
        // 1. 获取镜像路径，匹配 SDK 标识
        const char *imagePathC = _dyld_get_image_name(i);
        if (imagePathC == NULL) continue;
        
        NSString *imagePath = [NSString stringWithUTF8String:imagePathC];
        if (![imagePath containsString:libraryIdentifier]) {
            continue; // 不匹配，跳过
        }

        NSLog(@"[AnyThinkCrashFilter] 找到匹配的镜像：%@", imagePath);

        // 2. 获取 ASLR 偏移（修正随机地址）
        const intptr_t slide = _dyld_get_image_vmaddr_slide(i);
        if (slide < 0) {
            NSLog(@"[AnyThinkCrashFilter] 警告：ASLR 偏移无效 (%ld)，跳过该镜像", (long)slide);
            continue;
        }

        // 3. 获取 mach-o 头部信息
        const struct mach_header *header = _dyld_get_image_header(i);
        if (header == NULL) {
            NSLog(@"[AnyThinkCrashFilter] 警告：mach-o 头部为空，跳过该镜像");
            continue;
        }

        // 4. 计算地址范围（核心逻辑）
        [self calculateAddressRangeWithHeader:header slide:(uintptr_t)slide];
        
        // 5. 验证地址范围是否有效
        if (self.isAddressRangeValid) {
            NSLog(@"[AnyThinkCrashFilter] ✅ 地址范围初始化成功：0x%lx - 0x%lx (大小: %lu 字节)",
                  self.sdkStartAddress, self.sdkEndAddress,
                  (unsigned long)(self.sdkEndAddress - self.sdkStartAddress));
            return;
        } else {
            NSLog(@"[AnyThinkCrashFilter] 警告：计算的地址范围无效，继续搜索其他镜像");
            // 重置以便继续搜索
            self.sdkStartAddress = 0;
            self.sdkEndAddress = 0;
        }
    }

    NSLog(@"[AnyThinkCrashFilter] ❌ 未找到 '%@' 对应的有效镜像，筛选功能将失效", libraryIdentifier);
}

/// 解析 mach-o 结构，计算准确的地址范围
- (void)calculateAddressRangeWithHeader:(const struct mach_header *)header
                                 slide:(uintptr_t)slide {
    // 校验头部合法性
    if (header->magic != MH_MAGIC && header->magic != MH_MAGIC_64 &&
        header->magic != MH_CIGAM && header->magic != MH_CIGAM_64) {
        NSLog(@"[AnyThinkCrashFilter] 错误：无效的 mach-o 头部");
        return;
    }

    // 区分 64 位/32 位架构
    const BOOL is64Bit = (header->magic == MH_MAGIC_64 || header->magic == MH_CIGAM_64);
    const uintptr_t headerSize = is64Bit ? sizeof(struct mach_header_64) : sizeof(struct mach_header);

    // header 本身已经是加载后的地址（包含 ASLR 偏移）
    // 但我们还需要找到实际的段地址范围
    uintptr_t minStartAddress = UINTPTR_MAX;
    uintptr_t maxEndAddress = 0;

    // 遍历所有加载命令，计算实际的段地址范围
    const uint8_t *cmdPtr = (const uint8_t *)header + headerSize;
    const uint8_t *headerEnd = (const uint8_t *)header + headerSize + header->sizeofcmds;
    
    for (uint32_t i = 0; i < header->ncmds; i++) {
        // 校验命令边界（避免越界访问）
        if (cmdPtr + sizeof(struct load_command) > headerEnd) {
            NSLog(@"[AnyThinkCrashFilter] 警告：加载命令越界，提前退出");
            break;
        }

        const struct load_command *cmd = (const struct load_command *)cmdPtr;
        
        // 校验命令大小有效性
        if (cmd->cmdsize == 0 || cmd->cmdsize < sizeof(struct load_command)) {
            NSLog(@"[AnyThinkCrashFilter] 警告：无效的命令大小，跳过");
            cmdPtr += sizeof(struct load_command);
            continue;
        }

        // 校验下一个命令不会越界
        const uint8_t *nextCmdPtr = cmdPtr + cmd->cmdsize;
        if (nextCmdPtr > headerEnd) {
            NSLog(@"[AnyThinkCrashFilter] 警告：命令超出边界，提前退出");
            break;
        }

        // 处理段命令（SEGMENT/SEGMENT_64）
        if ((!is64Bit && cmd->cmd == LC_SEGMENT) || (is64Bit && cmd->cmd == LC_SEGMENT_64)) {
            if (is64Bit) {
                const struct segment_command_64 *segCmd = (const struct segment_command_64 *)cmd;
                // vmaddr 是虚拟地址，需要加上 slide 得到实际加载地址
                uintptr_t segStart = segCmd->vmaddr + slide;
                uintptr_t segEnd = segStart + segCmd->vmsize;
                
                if (segStart < minStartAddress) {
                    minStartAddress = segStart;
                }
                if (segEnd > maxEndAddress) {
                    maxEndAddress = segEnd;
                }
            } else {
                const struct segment_command *segCmd = (const struct segment_command *)cmd;
                // vmaddr 是虚拟地址，需要加上 slide 得到实际加载地址
                uintptr_t segStart = segCmd->vmaddr + slide;
                uintptr_t segEnd = segStart + segCmd->vmsize;
                
                if (segStart < minStartAddress) {
                    minStartAddress = segStart;
                }
                if (segEnd > maxEndAddress) {
                    maxEndAddress = segEnd;
                }
            }
        }

        cmdPtr = nextCmdPtr;
    }

    // 保存计算结果（带有效性校验）
    if (minStartAddress != UINTPTR_MAX && maxEndAddress > minStartAddress) {
        self.sdkStartAddress = minStartAddress;
        self.sdkEndAddress = maxEndAddress;
        NSLog(@"[AnyThinkCrashFilter] 地址范围计算成功：0x%lx - 0x%lx (大小: %lu 字节)",
              self.sdkStartAddress, self.sdkEndAddress,
              (unsigned long)(self.sdkEndAddress - self.sdkStartAddress));
    } else {
        // 如果没找到段，使用 header 地址作为备选方案
        uintptr_t fallbackStart = (uintptr_t)header;
        uintptr_t fallbackEnd = fallbackStart + headerSize + header->sizeofcmds;
        self.sdkStartAddress = fallbackStart;
        self.sdkEndAddress = fallbackEnd;
        NSLog(@"[AnyThinkCrashFilter] 警告：使用备选地址范围：0x%lx - 0x%lx", 
              self.sdkStartAddress, self.sdkEndAddress);
    }
}

#pragma mark - 筛选崩溃报告
- (BOOL)shouldReportCrash:(NSDictionary *)crashReport {
    // 安全校验：地址范围无效时，不上报任何崩溃
    if (!self.isAddressRangeValid) {
        NSLog(@"[AnyThinkCrashFilter] 地址范围未初始化，跳过崩溃报告");
        return NO;
    }

    // 1. 获取 crash 字典
    NSDictionary *crashDict = crashReport[@"crash"];
    if (![crashDict isKindOfClass:NSDictionary.class]) {
        NSLog(@"[AnyThinkCrashFilter] 崩溃报告格式错误：缺少 crash 字段");
        return NO;
    }

    // 2. 获取崩溃线程（优先处理标记为 crashed 的线程）
    NSDictionary *crashedThread = [self findCrashedThreadInReport:crashDict];
    if (!crashedThread) {
        NSLog(@"[AnyThinkCrashFilter] 未找到崩溃线程");
        return NO;
    }

    // 3. 解析崩溃线程的栈帧（backtrace 是字典，包含 contents 数组）
    NSDictionary *backtraceDict = crashedThread[@"backtrace"];
    if (![backtraceDict isKindOfClass:NSDictionary.class]) {
        NSLog(@"[AnyThinkCrashFilter] 栈帧数据格式错误：backtrace 不是字典");
        return NO;
    }

    NSArray *contents = backtraceDict[@"contents"];
    if (![contents isKindOfClass:NSArray.class] || contents.count == 0) {
        NSLog(@"[AnyThinkCrashFilter] 栈帧内容为空");
        return NO;
    }

    // 4. 检查是否有地址落在 AnyThinkSDK 范围内
    for (id frameObj in contents) {
        if (![frameObj isKindOfClass:NSDictionary.class]) {
            continue;
        }
        
        NSDictionary *frame = (NSDictionary *)frameObj;
        
        // 优先使用 instruction_addr（指令地址），这是最准确的
        id addrObj = frame[@"instruction_addr"];
        if (addrObj) {
            uintptr_t address = [self parseAddressFromObject:addrObj];
            if (address > 0 && [self isAddressInSDKRange:address]) {
                NSLog(@"[AnyThinkCrashFilter] 在栈帧中找到 SDK 地址：0x%lx（instruction_addr）", address);
                return YES;
            }
        }
        
        // 备选：使用 object_addr（对象地址）
        addrObj = frame[@"object_addr"];
        if (addrObj) {
            uintptr_t address = [self parseAddressFromObject:addrObj];
            if (address > 0 && [self isAddressInSDKRange:address]) {
                NSLog(@"[AnyThinkCrashFilter] 在栈帧中找到 SDK 地址：0x%lx（object_addr）", address);
                return YES;
            }
        }
    }

    // 5. 可选：检查 binary_images 中的 SDK 地址范围（更准确的验证）
    if ([self checkBinaryImagesInReport:crashReport]) {
        return YES;
    }

    NSLog(@"[AnyThinkCrashFilter] 未找到 SDK 相关崩溃，过滤该报告");
    return NO; // 非 SDK 崩溃，不上报
}

/// 从崩溃报告中找到崩溃的线程
- (nullable NSDictionary *)findCrashedThreadInReport:(NSDictionary *)crashDict {
    if (![crashDict isKindOfClass:NSDictionary.class]) {
        return nil;
    }
    
    NSArray *threads = crashDict[@"threads"];
    if (![threads isKindOfClass:NSArray.class] || threads.count == 0) {
        return nil;
    }

    // 优先返回标记为 crashed 的线程
    for (id threadObj in threads) {
        if (![threadObj isKindOfClass:NSDictionary.class]) {
            continue;
        }
        NSDictionary *thread = (NSDictionary *)threadObj;
        id crashedObj = thread[@"crashed"];
        if ([crashedObj isKindOfClass:NSNumber.class] && [crashedObj boolValue]) {
            return thread;
        }
    }

    // 未找到崩溃线程时，返回第一个线程（降级处理）
    return threads.firstObject;
}

/// 从对象中解析内存地址（支持 NSNumber 和 NSString）
- (uintptr_t)parseAddressFromObject:(id)addrObj {
    if (!addrObj) {
        return 0;
    }
    
    // 如果是 NSNumber，直接转换
    if ([addrObj isKindOfClass:NSNumber.class]) {
        NSNumber *number = (NSNumber *)addrObj;
        uint64_t value = [number unsignedLongLongValue];
        return (uintptr_t)value;
    }
    
    // 如果是 NSString，尝试解析十六进制字符串
    if ([addrObj isKindOfClass:NSString.class]) {
        NSString *frame = (NSString *)addrObj;
        if (frame.length == 0) {
            return 0;
        }

        // 提取字符串中的十六进制地址（忽略非十六进制字符）
        NSMutableString *hexString = [NSMutableString string];
        for (NSUInteger i = 0; i < frame.length; i++) {
            unichar c = [frame characterAtIndex:i];
            if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
                [hexString appendFormat:@"%C", c];
            }
        }

        // 转换为 uintptr_t（地址值）
        if (hexString.length == 0) {
            return 0;
        }
        uint64_t address64;
        NSScanner *scanner = [NSScanner scannerWithString:hexString];
        if ([scanner scanHexLongLong:&address64]) {
            return (uintptr_t)address64;
        }
    }
    
    return 0;
}

/// 判断地址是否在 SDK 地址范围内
- (BOOL)isAddressInSDKRange:(uintptr_t)address {
    return (address >= self.sdkStartAddress && address <= self.sdkEndAddress);
}

/// 检查 binary_images 中是否包含 SDK 的镜像信息（辅助验证）
- (BOOL)checkBinaryImagesInReport:(NSDictionary *)crashReport {
    NSArray *binaryImages = crashReport[@"binary_images"];
    if (![binaryImages isKindOfClass:NSArray.class]) {
        return NO;
    }
    
    // 检查 binary_images 中是否有地址范围与 SDK 地址范围重叠的镜像
    for (id imageObj in binaryImages) {
        if (![imageObj isKindOfClass:NSDictionary.class]) {
            continue;
        }
        
        NSDictionary *image = (NSDictionary *)imageObj;
        id addrObj = image[@"image_addr"];
        id sizeObj = image[@"image_size"];
        
        if (!addrObj || !sizeObj) {
            continue;
        }
        
        uintptr_t imageAddr = [self parseAddressFromObject:addrObj];
        uintptr_t imageSize = [self parseAddressFromObject:sizeObj];
        
        if (imageAddr > 0 && imageSize > 0) {
            uintptr_t imageEnd = imageAddr + imageSize;
            // 检查地址范围是否重叠
            if (imageAddr <= self.sdkEndAddress && imageEnd >= self.sdkStartAddress) {
                // 进一步检查对象名称（如果有 SDK 标识符）
                NSString *imageName = image[@"name"];
                if (imageName && [imageName isKindOfClass:NSString.class]) {
                    // 如果镜像名称包含 SDK 标识，则更确定
                    NSLog(@"[AnyThinkCrashFilter] 在 binary_images 中找到可能的 SDK 镜像：%@", imageName);
                }
                return YES;
            }
        }
    }
    
    return NO;
}

@end
